home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / unix / tkUnixMenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  44.0 KB  |  1,614 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkUnixMenu.c --
  3.  *
  4.  *    This module implements the UNIX platform-specific features of menus.
  5.  *
  6.  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * SCCS: @(#) tkUnixMenu.c 1.74 97/08/08 17:31:00
  12.  */
  13.  
  14. #include "tkPort.h"
  15. #include "default.h"
  16. #include "tkInt.h"
  17. #include "tkUnixInt.h"
  18. #include "tkMenu.h"
  19.  
  20. /*
  21.  * Constants used for menu drawing.
  22.  */
  23.  
  24. #define MENU_MARGIN_WIDTH    2
  25. #define MENU_DIVIDER_HEIGHT    2
  26.  
  27. /*
  28.  * Platform specific flags for Unix.
  29.  */
  30.  
  31. #define ENTRY_HELP_MENU        ENTRY_PLATFORM_FLAG1
  32.  
  33. /*
  34.  * Procedures used internally.
  35.  */
  36.  
  37. static void        SetHelpMenu _ANSI_ARGS_((TkMenu *menuPtr));
  38. static void        DrawMenuEntryAccelerator _ANSI_ARGS_((
  39.                 TkMenu *menuPtr, TkMenuEntry *mePtr, 
  40.                 Drawable d, GC gc, Tk_Font tkfont,
  41.                 CONST Tk_FontMetrics *fmPtr,
  42.                 Tk_3DBorder activeBorder, int x, int y,
  43.                 int width, int height, int drawArrow));
  44. static void        DrawMenuEntryBackground _ANSI_ARGS_((
  45.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  46.                 Drawable d, Tk_3DBorder activeBorder,
  47.                 Tk_3DBorder bgBorder, int x, int y,
  48.                 int width, int heigth));
  49. static void        DrawMenuEntryIndicator _ANSI_ARGS_((
  50.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  51.                 Drawable d, GC gc, GC indicatorGC, 
  52.                 Tk_Font tkfont,
  53.                 CONST Tk_FontMetrics *fmPtr, int x, int y,
  54.                 int width, int height));
  55. static void        DrawMenuEntryLabel _ANSI_ARGS_((
  56.                 TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d,
  57.                 GC gc, Tk_Font tkfont,
  58.                 CONST Tk_FontMetrics *fmPtr, int x, int y,
  59.                 int width, int height));
  60. static void        DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr,
  61.                 TkMenuEntry *mePtr, Drawable d, GC gc, 
  62.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  63.                 int x, int y, int width, int height));
  64. static void        DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr,
  65.                 TkMenuEntry *mePtr, Drawable d, GC gc, 
  66.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  67.                 int x, int y, int width, int height));
  68. static void        DrawMenuUnderline _ANSI_ARGS_((TkMenu *menuPtr,
  69.                 TkMenuEntry *mePtr, Drawable d, GC gc,
  70.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x,
  71.                 int y, int width, int height));
  72. static void        GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  73.                 TkMenuEntry *mePtr, Tk_Font tkfont,
  74.                 CONST Tk_FontMetrics *fmPtr, int *widthPtr,
  75.                 int *heightPtr));
  76. static void        GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr,
  77.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  78.                 int *widthPtr, int *heightPtr));
  79. static void        GetMenuIndicatorGeometry _ANSI_ARGS_((
  80.                 TkMenu *menuPtr, TkMenuEntry *mePtr, 
  81.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  82.                 int *widthPtr, int *heightPtr));
  83. static void        GetMenuSeparatorGeometry _ANSI_ARGS_((
  84.                 TkMenu *menuPtr, TkMenuEntry *mePtr,
  85.                 Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  86.                 int *widthPtr, int *heightPtr));
  87. static void        GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  88.                 TkMenuEntry *mePtr, Tk_Font tkfont,
  89.                 CONST Tk_FontMetrics *fmPtr, int *widthPtr,
  90.                 int *heightPtr));
  91.  
  92.  
  93. /*
  94.  *----------------------------------------------------------------------
  95.  *
  96.  * TkpNewMenu --
  97.  *
  98.  *    Gets the platform-specific piece of the menu. Invoked during idle
  99.  *    after the generic part of the menu has been created.
  100.  *
  101.  * Results:
  102.  *    Standard TCL error.
  103.  *
  104.  * Side effects:
  105.  *    Allocates any platform specific allocations and places them
  106.  *    in the platformData field of the menuPtr.
  107.  *
  108.  *----------------------------------------------------------------------
  109.  */
  110.  
  111. int
  112. TkpNewMenu(menuPtr)
  113.     TkMenu *menuPtr;
  114. {
  115.     SetHelpMenu(menuPtr);
  116.     return TCL_OK;
  117. }
  118.  
  119. /*
  120.  *----------------------------------------------------------------------
  121.  *
  122.  * TkpDestroyMenu --
  123.  *
  124.  *    Destroys platform-specific menu structures. Called when the
  125.  *    generic menu structure is destroyed for the menu.
  126.  *
  127.  * Results:
  128.  *    None.
  129.  *
  130.  * Side effects:
  131.  *    All platform-specific allocations are freed up.
  132.  *
  133.  *----------------------------------------------------------------------
  134.  */
  135.  
  136. void
  137. TkpDestroyMenu(menuPtr)
  138.     TkMenu *menuPtr;
  139. {
  140.     /*
  141.      * Nothing to do.
  142.      */
  143. }
  144.  
  145. /*
  146.  *----------------------------------------------------------------------
  147.  *
  148.  * TkpDestroyMenuEntry --
  149.  *
  150.  *    Cleans up platform-specific menu entry items. Called when entry
  151.  *    is destroyed in the generic code.
  152.  *
  153.  * Results:
  154.  *    None.
  155.  *
  156.  * Side effects:
  157.  *    All platform specific allocations are freed up.
  158.  *
  159.  *----------------------------------------------------------------------
  160.  */
  161.  
  162. void
  163. TkpDestroyMenuEntry(mEntryPtr)
  164.     TkMenuEntry *mEntryPtr;
  165. {
  166.     /*
  167.      * Nothing to do.
  168.      */
  169. }
  170.  
  171. /*
  172.  *----------------------------------------------------------------------
  173.  *
  174.  * TkpConfigureMenuEntry --
  175.  *
  176.  *    Processes configuration options for menu entries. Called when
  177.  *    the generic options are processed for the menu.
  178.  *
  179.  * Results:
  180.  *    Returns standard TCL result. If TCL_ERROR is returned, then
  181.  *    interp->result contains an error message.
  182.  *
  183.  * Side effects:
  184.  *    Configuration information get set for mePtr; old resources
  185.  *    get freed, if any need it.
  186.  *
  187.  *----------------------------------------------------------------------
  188.  */
  189.  
  190. int
  191. TkpConfigureMenuEntry(mePtr)
  192.     register TkMenuEntry *mePtr;    /* Information about menu entry;  may
  193.                      * or may not already have values for
  194.                      * some fields. */
  195. {
  196.     /*
  197.      * If this is a cascade menu, and the child menu exists, check to
  198.      * see if the child menu is a help menu.
  199.      */
  200.  
  201.     if ((mePtr->type == CASCADE_ENTRY) && (mePtr->name != NULL)) {
  202.     TkMenuReferences *menuRefPtr;
  203.  
  204.     menuRefPtr = TkFindMenuReferences(mePtr->menuPtr->interp,
  205.         mePtr->name);
  206.     if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) {
  207.         SetHelpMenu(menuRefPtr->menuPtr);
  208.     }
  209.     }
  210.     return TCL_OK;
  211. }
  212.  
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  * TkpMenuNewEntry --
  217.  *
  218.  *    Called when a new entry is created in a menu. Fills in platform
  219.  *    specific data for the entry. The platformEntryData field
  220.  *    is used to store the indicator diameter for radio button
  221.  *    and check box entries.
  222.  *
  223.  * Results:
  224.  *     Standard TCL error.
  225.  *
  226.  * Side effects:
  227.  *    None on Unix.
  228.  *
  229.  *----------------------------------------------------------------------
  230.  */
  231.  
  232. int
  233. TkpMenuNewEntry(mePtr)
  234.     TkMenuEntry *mePtr;
  235. {
  236.     return TCL_OK;
  237. }
  238.  
  239. /*
  240.  *----------------------------------------------------------------------
  241.  *
  242.  * TkpSetWindowMenuBar --
  243.  *
  244.  *    Sets up the menu as a menubar in the given window.
  245.  *
  246.  * Results:
  247.  *    None.
  248.  *
  249.  * Side effects:
  250.  *    Recomputes geometry of given window.
  251.  *
  252.  *----------------------------------------------------------------------
  253.  */
  254.  
  255. void
  256. TkpSetWindowMenuBar(tkwin, menuPtr)
  257.     Tk_Window tkwin;            /* The window we are setting */
  258.     TkMenu *menuPtr;            /* The menu we are setting */
  259. {
  260.     if (menuPtr == NULL) {
  261.     TkUnixSetMenubar(tkwin, NULL);
  262.     } else {
  263.     TkUnixSetMenubar(tkwin, menuPtr->tkwin);
  264.     }
  265. }
  266.  
  267. /*
  268.  *----------------------------------------------------------------------
  269.  *
  270.  * TkpSetMainMenuBar --
  271.  *
  272.  *    Called when a toplevel widget is brought to front. On the
  273.  *    Macintosh, sets up the menubar that goes accross the top
  274.  *    of the main monitor. On other platforms, nothing is necessary.
  275.  *
  276.  * Results:
  277.  *    None.
  278.  *
  279.  * Side effects:
  280.  *    Recompute geometry of given window.
  281.  *
  282.  *----------------------------------------------------------------------
  283.  */
  284.  
  285. void
  286. TkpSetMainMenubar(interp, tkwin, menuName)
  287.     Tcl_Interp *interp;
  288.     Tk_Window tkwin;
  289.     char *menuName;
  290. {
  291.     /*
  292.      * Nothing to do.
  293.      */
  294. }
  295.  
  296. /*
  297.  *----------------------------------------------------------------------
  298.  *
  299.  * GetMenuIndicatorGeometry --
  300.  *
  301.  *    Fills out the geometry of the indicator in a menu item. Note
  302.  *    that the mePtr->height field must have already been filled in
  303.  *    by GetMenuLabelGeometry since this height depends on the label
  304.  *    height.
  305.  *
  306.  * Results:
  307.  *    widthPtr and heightPtr point to the new geometry values.
  308.  *
  309.  * Side effects:
  310.  *    None.
  311.  *
  312.  *----------------------------------------------------------------------
  313.  */
  314.  
  315. static void
  316. GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  317.     TkMenu *menuPtr;            /* The menu we are drawing. */
  318.     TkMenuEntry *mePtr;            /* The entry we are interested in. */
  319.     Tk_Font tkfont;            /* The precalculated font */
  320.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated metrics */
  321.     int *widthPtr;            /* The resulting width */
  322.     int *heightPtr;            /* The resulting height */
  323. {
  324.     if (!mePtr->hideMargin && mePtr->indicatorOn &&
  325.         ((mePtr->type == CHECK_BUTTON_ENTRY)
  326.         || (mePtr->type == RADIO_BUTTON_ENTRY))) {
  327.         if ((mePtr->image != NULL) || (mePtr->bitmap != None)) {
  328.             *widthPtr = (14 * mePtr->height) / 10;
  329.             *heightPtr = mePtr->height;
  330.             if (mePtr->type == CHECK_BUTTON_ENTRY) {
  331.             mePtr->platformEntryData = 
  332.             (TkMenuPlatformEntryData) ((65 * mePtr->height) / 100);
  333.         } else {
  334.                 mePtr->platformEntryData = 
  335.             (TkMenuPlatformEntryData) ((75 * mePtr->height) / 100);
  336.             }                
  337.         } else {
  338.             *widthPtr = *heightPtr = mePtr->height;
  339.         if (mePtr->type == CHECK_BUTTON_ENTRY) {
  340.         mePtr->platformEntryData = (TkMenuPlatformEntryData)
  341.             ((80 * mePtr->height) / 100);
  342.         } else {
  343.         mePtr->platformEntryData = (TkMenuPlatformEntryData)
  344.             mePtr->height;
  345.         }
  346.     }
  347.     } else {
  348.         *heightPtr = 0;
  349.         *widthPtr = menuPtr->borderWidth;
  350.     }
  351. }
  352.  
  353.  
  354. /*
  355.  *----------------------------------------------------------------------
  356.  *
  357.  * GetMenuAccelGeometry --
  358.  *
  359.  *    Get the geometry of the accelerator area of a menu item.
  360.  *
  361.  * Results:
  362.  *    heightPtr and widthPtr are set.
  363.  *
  364.  * Side effects:
  365.  *    None.
  366.  *
  367.  *----------------------------------------------------------------------
  368.  */
  369.  
  370. static void
  371. GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  372.     TkMenu *menuPtr;        /* The menu was are drawing */
  373.     TkMenuEntry *mePtr;        /* The entry we are getting the geometry for */
  374.     Tk_Font tkfont;        /* The precalculated font */
  375.     CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics */
  376.     int *widthPtr;        /* The width of the acclerator area */
  377.     int *heightPtr;        /* The height of the accelerator area */
  378. {
  379.     *heightPtr = fmPtr->linespace;
  380.     if (mePtr->type == CASCADE_ENTRY) {
  381.         *widthPtr = 2 * CASCADE_ARROW_WIDTH;
  382.     } else if ((menuPtr->menuType != MENUBAR) && (mePtr->accel != NULL)) {
  383.         *widthPtr = Tk_TextWidth(tkfont, mePtr->accel, mePtr->accelLength);
  384.     } else {
  385.         *widthPtr = 0;
  386.     }
  387. }
  388.  
  389. /*
  390.  *----------------------------------------------------------------------
  391.  *
  392.  * DrawMenuEntryBackground --
  393.  *
  394.  *    This procedure draws the background part of a menu.
  395.  *
  396.  * Results:
  397.  *    None.
  398.  *
  399.  * Side effects:
  400.  *    Commands are output to X to display the menu in its
  401.  *    current mode.
  402.  *
  403.  *----------------------------------------------------------------------
  404.  */
  405.  
  406. static void
  407. DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y,
  408.     width, height)
  409.     TkMenu *menuPtr;        /* The menu we are drawing */
  410.     TkMenuEntry *mePtr;        /* The entry we are drawing. */
  411.     Drawable d;            /* The drawable we are drawing into */
  412.     Tk_3DBorder activeBorder;    /* The border for an active item */
  413.     Tk_3DBorder bgBorder;    /* The background border */
  414.     int x;            /* Left coordinate of entry rect */
  415.     int y;            /* Right coordinate of entry rect */
  416.     int width;            /* Width of entry rect */
  417.     int height;            /* Height of entry rect */
  418. {
  419.     if (mePtr->state == tkActiveUid) {
  420.     int relief;
  421.         bgBorder = activeBorder;
  422.  
  423.     if ((menuPtr->menuType == MENUBAR)
  424.         && ((menuPtr->postedCascade == NULL)
  425.         || (menuPtr->postedCascade != mePtr))) {
  426.         relief = TK_RELIEF_FLAT;
  427.     } else {
  428.         relief = TK_RELIEF_RAISED;
  429.     }
  430.     
  431.     Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
  432.         menuPtr->activeBorderWidth, relief);
  433.     } else {
  434.     Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
  435.         0, TK_RELIEF_FLAT);
  436.     }
  437. }
  438.  
  439. /*
  440.  *----------------------------------------------------------------------
  441.  *
  442.  * DrawMenuEntryAccelerator --
  443.  *
  444.  *    This procedure draws the background part of a menu.
  445.  *
  446.  * Results:
  447.  *    None.
  448.  *
  449.  * Side effects:
  450.  *    Commands are output to X to display the menu in its
  451.  *    current mode.
  452.  *
  453.  *----------------------------------------------------------------------
  454.  */
  455.  
  456. static void
  457. DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder,
  458.     x, y, width, height, drawArrow)
  459.     TkMenu *menuPtr;            /* The menu we are drawing */
  460.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  461.     Drawable d;                /* The drawable we are drawing into */
  462.     GC gc;                /* The precalculated gc to draw with */
  463.     Tk_Font tkfont;            /* The precalculated font */
  464.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated metrics */
  465.     Tk_3DBorder activeBorder;        /* The border for an active item */
  466.     int x;                /* Left coordinate of entry rect */
  467.     int y;                /* Top coordinate of entry rect */
  468.     int width;                /* Width of entry */
  469.     int height;                /* Height of entry */
  470.     int drawArrow;            /* Whether or not to draw arrow. */
  471. {
  472.     XPoint points[3];
  473.     
  474.     /*
  475.      * Draw accelerator or cascade arrow.
  476.      */
  477.  
  478.     if (menuPtr->menuType == MENUBAR) {
  479.     return;
  480.     }
  481.  
  482.     if ((mePtr->type == CASCADE_ENTRY) && drawArrow) {
  483.         points[0].x = x + width - menuPtr->borderWidth
  484.             - menuPtr->activeBorderWidth - CASCADE_ARROW_WIDTH;
  485.         points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2;
  486.         points[1].x = points[0].x;
  487.         points[1].y = points[0].y + CASCADE_ARROW_HEIGHT;
  488.         points[2].x = points[0].x + CASCADE_ARROW_WIDTH;
  489.         points[2].y = points[0].y + CASCADE_ARROW_HEIGHT/2;
  490.         Tk_Fill3DPolygon(menuPtr->tkwin, d, activeBorder, points, 3,
  491.         DECORATION_BORDER_WIDTH,
  492.             (menuPtr->postedCascade == mePtr)
  493.             ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
  494.     } else if (mePtr->accel != NULL) {
  495.     int left = x + mePtr->labelWidth + menuPtr->activeBorderWidth
  496.             + mePtr->indicatorSpace;
  497.     if (menuPtr->menuType == MENUBAR) {
  498.         left += 5;
  499.     }
  500.         Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel,
  501.         mePtr->accelLength, left,
  502.         (y + (height + fmPtr->ascent - fmPtr->descent) / 2));
  503.     }
  504. }
  505.  
  506. /*
  507.  *----------------------------------------------------------------------
  508.  *
  509.  * DrawMenuEntryIndicator --
  510.  *
  511.  *    This procedure draws the background part of a menu.
  512.  *
  513.  * Results:
  514.  *    None.
  515.  *
  516.  * Side effects:
  517.  *    Commands are output to X to display the menu in its
  518.  *    current mode.
  519.  *
  520.  *----------------------------------------------------------------------
  521.  */
  522.  
  523. static void
  524. DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr,
  525.     x, y, width, height)
  526.     TkMenu *menuPtr;            /* The menu we are drawing */
  527.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  528.     Drawable d;                /* The drawable to draw into */
  529.     GC gc;                /* The gc to draw with */
  530.     GC indicatorGC;            /* The gc that indicators draw with */
  531.     Tk_Font tkfont;            /* The font to draw with */
  532.     CONST Tk_FontMetrics *fmPtr;    /* The font metrics of the font */
  533.     int x;                /* The left of the entry rect */
  534.     int y;                /* The top of the entry rect */
  535.     int width;                /* Width of menu entry */
  536.     int height;                /* Height of menu entry */
  537. {
  538.  
  539.     /*
  540.      * Draw check-button indicator.
  541.      */
  542.  
  543.     if ((mePtr->type == CHECK_BUTTON_ENTRY)
  544.         && mePtr->indicatorOn) {
  545.         int dim, top, left;
  546.     
  547.     dim = (int) mePtr->platformEntryData;
  548.         left = x + menuPtr->activeBorderWidth
  549.         + (mePtr->indicatorSpace - dim)/2;
  550.     if (menuPtr->menuType == MENUBAR) {
  551.         left += 5;
  552.     }
  553.         top = y + (height - dim)/2;
  554.         Tk_Fill3DRectangle(menuPtr->tkwin, d, menuPtr->border, left, top, dim,
  555.         dim, DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
  556.         left += DECORATION_BORDER_WIDTH;
  557.         top += DECORATION_BORDER_WIDTH;
  558.         dim -= 2*DECORATION_BORDER_WIDTH;
  559.         if ((dim > 0) && (mePtr->entryFlags
  560.             & ENTRY_SELECTED)) {
  561.         XFillRectangle(menuPtr->display, d, indicatorGC, left, top,
  562.             (unsigned int) dim, (unsigned int) dim);
  563.         }
  564.     }
  565.  
  566.     /*
  567.      * Draw radio-button indicator.
  568.      */
  569.  
  570.     if ((mePtr->type == RADIO_BUTTON_ENTRY)
  571.         && mePtr->indicatorOn) {
  572.         XPoint points[4];
  573.         int radius;
  574.  
  575.     radius = ((int) mePtr->platformEntryData)/2;
  576.         points[0].x = x + (mePtr->indicatorSpace
  577.         - (int) mePtr->platformEntryData)/2;
  578.     points[0].y = y + (height)/2;
  579.         points[1].x = points[0].x + radius;
  580.         points[1].y = points[0].y + radius;
  581.         points[2].x = points[1].x + radius;
  582.         points[2].y = points[0].y;
  583.         points[3].x = points[1].x;
  584.         points[3].y = points[0].y - radius;
  585.         if (mePtr->entryFlags & ENTRY_SELECTED) {
  586.         XFillPolygon(menuPtr->display, d, indicatorGC, points, 4, Convex,
  587.             CoordModeOrigin);
  588.         } else {
  589.         Tk_Fill3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 4,
  590.             DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT);
  591.         }
  592.         Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 4,
  593.             DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
  594.     }
  595. }
  596.  
  597. /*
  598.  *----------------------------------------------------------------------
  599.  *
  600.  * DrawMenuSeparator --
  601.  *
  602.  *    This procedure draws a separator menu item.
  603.  *
  604.  * Results:
  605.  *    None.
  606.  *
  607.  * Side effects:
  608.  *    Commands are output to X to display the menu in its
  609.  *    current mode.
  610.  *
  611.  *----------------------------------------------------------------------
  612.  */
  613.  
  614. static void
  615. DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  616.     TkMenu *menuPtr;            /* The menu we are drawing */
  617.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  618.     Drawable d;                /* The drawable we are using */
  619.     GC gc;                /* The gc to draw into */
  620.     Tk_Font tkfont;            /* The font to draw with */
  621.     CONST Tk_FontMetrics *fmPtr;    /* The font metrics from the font */
  622.     int x;
  623.     int y;
  624.     int width;
  625.     int height;
  626. {
  627.     XPoint points[2];
  628.     int margin;
  629.  
  630.     if (menuPtr->menuType == MENUBAR) {
  631.     return;
  632.     }
  633.     
  634.     margin = (fmPtr->ascent + fmPtr->descent)/2;
  635.     points[0].x = x;
  636.     points[0].y = y + height/2;
  637.     points[1].x = width - 1;
  638.     points[1].y = points[0].y;
  639.     Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1,
  640.         TK_RELIEF_RAISED);
  641. }
  642.  
  643. /*
  644.  *----------------------------------------------------------------------
  645.  *
  646.  * DrawMenuEntryLabel --
  647.  *
  648.  *    This procedure draws the label part of a menu.
  649.  *
  650.  * Results:
  651.  *    None.
  652.  *
  653.  * Side effects:
  654.  *    Commands are output to X to display the menu in its
  655.  *    current mode.
  656.  *
  657.  *----------------------------------------------------------------------
  658.  */
  659.  
  660. static void
  661. DrawMenuEntryLabel(
  662.     menuPtr,            /* The menu we are drawing */
  663.     mePtr,            /* The entry we are drawing */
  664.     d,                /* What we are drawing into */
  665.     gc,                /* The gc we are drawing into */
  666.     tkfont,            /* The precalculated font */
  667.     fmPtr,            /* The precalculated font metrics */
  668.     x,                /* left edge */
  669.     y,                /* right edge */
  670.     width,            /* width of entry */
  671.     height)            /* height of entry */
  672.     TkMenu *menuPtr;
  673.     TkMenuEntry *mePtr;
  674.     Drawable d;
  675.     GC gc;
  676.     Tk_Font tkfont;
  677.     CONST Tk_FontMetrics *fmPtr;
  678.     int x, y, width, height;
  679. {
  680.     int baseline;
  681.     int indicatorSpace =  mePtr->indicatorSpace;
  682.     int leftEdge = x + indicatorSpace + menuPtr->activeBorderWidth;
  683.     int imageHeight, imageWidth;
  684.  
  685.     if (menuPtr->menuType == MENUBAR) {
  686.     leftEdge += 5;
  687.     }
  688.     
  689.     /*
  690.      * Draw label or bitmap or image for entry.
  691.      */
  692.  
  693.     baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  694.     if (mePtr->image != NULL) {
  695.         Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
  696.         if ((mePtr->selectImage != NULL)
  697.             && (mePtr->entryFlags & ENTRY_SELECTED)) {
  698.         Tk_RedrawImage(mePtr->selectImage, 0, 0,
  699.             imageWidth, imageHeight, d, leftEdge,
  700.                 (int) (y + (mePtr->height - imageHeight)/2));
  701.         } else {
  702.         Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
  703.             imageHeight, d, leftEdge,
  704.             (int) (y + (mePtr->height - imageHeight)/2));
  705.         }
  706.     } else if (mePtr->bitmap != None) {
  707.         int width, height;
  708.  
  709.         Tk_SizeOfBitmap(menuPtr->display,
  710.             mePtr->bitmap, &width, &height);
  711.         XCopyPlane(menuPtr->display,
  712.             mePtr->bitmap, d,
  713.             gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge,
  714.             (int) (y + (mePtr->height - height)/2), 1);
  715.     } else {
  716.         if (mePtr->labelLength > 0) {
  717.         Tk_DrawChars(menuPtr->display, d, gc,
  718.             tkfont, mePtr->label, mePtr->labelLength,
  719.             leftEdge, baseline);
  720.         DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y,
  721.             width, height);
  722.         }
  723.     }
  724.  
  725.     if (mePtr->state == tkDisabledUid) {
  726.     if (menuPtr->disabledFg == NULL) {
  727.         XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
  728.             (unsigned) width, (unsigned) height);
  729.     } else if ((mePtr->image != NULL) 
  730.         && (menuPtr->disabledImageGC != None)) {
  731.         XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  732.             leftEdge,
  733.             (int) (y + (mePtr->height - imageHeight)/2),
  734.             (unsigned) imageWidth, (unsigned) imageHeight);
  735.     }
  736.     }
  737. }
  738.  
  739. /*
  740.  *----------------------------------------------------------------------
  741.  *
  742.  * DrawMenuUnderline --
  743.  *
  744.  *    On appropriate platforms, draw the underline character for the
  745.  *    menu.
  746.  *
  747.  * Results:
  748.  *    None.
  749.  *
  750.  * Side effects:
  751.  *    Commands are output to X to display the menu in its
  752.  *    current mode.
  753.  *
  754.  *----------------------------------------------------------------------
  755.  */
  756.  
  757. static void
  758. DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  759.     TkMenu *menuPtr;            /* The menu to draw into */
  760.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  761.     Drawable d;                /* What we are drawing into */
  762.     GC gc;                /* The gc to draw into */
  763.     Tk_Font tkfont;            /* The precalculated font */
  764.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated font metrics */
  765.     int x;
  766.     int y;
  767.     int width;
  768.     int height;
  769. {
  770.     int indicatorSpace = mePtr->indicatorSpace;
  771.     if (mePtr->underline >= 0) {
  772.     int leftEdge = x + indicatorSpace + menuPtr->activeBorderWidth;
  773.     if (menuPtr->menuType == MENUBAR) {
  774.         leftEdge += 5;
  775.     }
  776.     
  777.         Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, mePtr->label,
  778.             leftEdge, y + (height + fmPtr->ascent - fmPtr->descent) / 2,
  779.         mePtr->underline, mePtr->underline + 1);
  780.     }        
  781. }
  782.  
  783. /*
  784.  *----------------------------------------------------------------------
  785.  *
  786.  * TkpPostMenu --
  787.  *
  788.  *    Posts a menu on the screen
  789.  *
  790.  * Results:
  791.  *    None.
  792.  *
  793.  * Side effects:
  794.  *    The menu is posted and handled.
  795.  *
  796.  *----------------------------------------------------------------------
  797.  */
  798.  
  799. int
  800. TkpPostMenu(interp, menuPtr, x, y)
  801.     Tcl_Interp *interp;
  802.     TkMenu *menuPtr;
  803.     int x;
  804.     int y;
  805. {
  806.     return TkPostTearoffMenu(interp, menuPtr, x, y);
  807. }
  808.  
  809. /*
  810.  *----------------------------------------------------------------------
  811.  *
  812.  * GetMenuSeparatorGeometry --
  813.  *
  814.  *    Gets the width and height of the indicator area of a menu.
  815.  *
  816.  * Results:
  817.  *    widthPtr and heightPtr are set.
  818.  *
  819.  * Side effects:
  820.  *    None.
  821.  *
  822.  *----------------------------------------------------------------------
  823.  */
  824.  
  825. static void
  826. GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr,
  827.     heightPtr) 
  828.     TkMenu *menuPtr;            /* The menu we are measuring */
  829.     TkMenuEntry *mePtr;            /* The entry we are measuring */
  830.     Tk_Font tkfont;            /* The precalculated font */
  831.     CONST Tk_FontMetrics *fmPtr;    /* The precalcualted font metrics */
  832.     int *widthPtr;            /* The resulting width */
  833.     int *heightPtr;            /* The resulting height */
  834. {
  835.     *widthPtr = 0;
  836.     *heightPtr = fmPtr->linespace;
  837. }
  838.  
  839. /*
  840.  *----------------------------------------------------------------------
  841.  *
  842.  * GetTearoffEntryGeometry --
  843.  *
  844.  *    Gets the width and height of the indicator area of a menu.
  845.  *
  846.  * Results:
  847.  *    widthPtr and heightPtr are set.
  848.  *
  849.  * Side effects:
  850.  *    None.
  851.  *
  852.  *----------------------------------------------------------------------
  853.  */
  854.  
  855. static void
  856. GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  857.     TkMenu *menuPtr;            /* The menu we are drawing */
  858.     TkMenuEntry *mePtr;            /* The entry we are measuring */
  859.     Tk_Font tkfont;            /* The precalculated font */
  860.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated font metrics */
  861.     int *widthPtr;            /* The resulting width */
  862.     int *heightPtr;            /* The resulting height */
  863. {
  864.     if (menuPtr->menuType != MASTER_MENU) {
  865.     *heightPtr = 0;
  866.     *widthPtr = 0;
  867.     } else {
  868.     *heightPtr = fmPtr->linespace;
  869.     *widthPtr = Tk_TextWidth(tkfont, "W", -1);
  870.     }
  871. }
  872.  
  873. /*
  874.  *--------------------------------------------------------------
  875.  *
  876.  * TkpComputeMenubarGeometry --
  877.  *
  878.  *    This procedure is invoked to recompute the size and
  879.  *    layout of a menu that is a menubar clone.
  880.  *
  881.  * Results:
  882.  *    None.
  883.  *
  884.  * Side effects:
  885.  *    Fields of menu entries are changed to reflect their
  886.  *    current positions, and the size of the menu window
  887.  *    itself may be changed.
  888.  *
  889.  *--------------------------------------------------------------
  890.  */
  891.  
  892. void
  893. TkpComputeMenubarGeometry(menuPtr)
  894.     TkMenu *menuPtr;        /* Structure describing menu. */
  895. {
  896.     Tk_Font tkfont;
  897.     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
  898.     int width, height;
  899.     int i, j;
  900.     int x, y, currentRowHeight, currentRowWidth, maxWidth;
  901.     int maxWindowWidth;
  902.     int lastRowBreak;
  903.     int itemHeight = 0;
  904.     int helpMenuIndex = -1;
  905.     TkMenuEntry *mePtr;
  906.     int lastEntry;
  907.     
  908.     if (menuPtr->tkwin == NULL) {
  909.     return;
  910.     }
  911.  
  912.     maxWidth = 0;
  913.     if (menuPtr->numEntries == 0) {
  914.     height = 0;
  915.     } else {
  916.     maxWindowWidth = Tk_Width(menuPtr->tkwin);
  917.     if (maxWindowWidth == 1) {
  918.         maxWindowWidth = 0x7ffffff;
  919.     }
  920.     currentRowHeight = 0;
  921.     x = y = menuPtr->borderWidth;
  922.     lastRowBreak = 0;
  923.     currentRowWidth = 0;
  924.     
  925.     /*
  926.      * On the Mac especially, getting font metrics can be quite slow,
  927.      * so we want to do it intelligently. We are going to precalculate
  928.      * them and pass them down to all of the measureing and drawing
  929.      * routines. We will measure the font metrics of the menu once,
  930.      * and if an entry has a font set, we will measure it as we come
  931.      * to it, and then we decide which set to give the geometry routines.
  932.      */
  933.     
  934.     Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics);
  935.     
  936.     for (i = 0; i < menuPtr->numEntries; i++) {
  937.         mePtr = menuPtr->entries[i];
  938.         mePtr->entryFlags &= ~ENTRY_LAST_COLUMN;
  939.         tkfont = mePtr->tkfont;
  940.         if (tkfont == NULL) {
  941.         tkfont = menuPtr->tkfont;
  942.         fmPtr = &menuMetrics;
  943.         } else {
  944.         Tk_GetFontMetrics(tkfont, &entryMetrics);
  945.         fmPtr = &entryMetrics;
  946.         }
  947.         
  948.         /*
  949.          * For every entry, we need to check to see whether or not we
  950.          * wrap. If we do wrap, then we have to adjust all of the previous
  951.          * entries' height and y position, because when we see them
  952.          * the first time, we don't know how big its neighbor might
  953.          * be.
  954.          */
  955.         
  956.         if ((mePtr->type == SEPARATOR_ENTRY)
  957.             || (mePtr->type == TEAROFF_ENTRY)) {
  958.         mePtr->height = mePtr->width = 0;
  959.         } else {
  960.         
  961.         GetMenuLabelGeometry(mePtr, tkfont, fmPtr,
  962.             &width, &height);
  963.         itemHeight = height;
  964.         mePtr->width = width;
  965.         
  966.         GetMenuIndicatorGeometry(menuPtr, mePtr,
  967.             tkfont, fmPtr, &width, &height);
  968.         mePtr->indicatorSpace = width;
  969.         if (width > 0) {
  970.             mePtr->width += width;
  971.         }
  972.         if (height > itemHeight) {
  973.             itemHeight = height;
  974.         }
  975.         itemHeight += 2 * menuPtr->activeBorderWidth;
  976.         mePtr->width += 2 * menuPtr->activeBorderWidth;
  977.         if (menuPtr->menuType == MENUBAR) {
  978.             itemHeight += 10;
  979.             mePtr->width += 10;
  980.         }
  981.         mePtr->height = itemHeight;
  982.         }
  983.         if (mePtr->entryFlags & ENTRY_HELP_MENU) {
  984.         helpMenuIndex = i;
  985.         } else if (x + mePtr->width + menuPtr->borderWidth
  986.             > maxWindowWidth) {
  987.  
  988.         if (i == lastRowBreak) {
  989.             mePtr->y = y;
  990.             mePtr->x = x;
  991.             lastRowBreak++;
  992.             y += mePtr->height;
  993.             currentRowHeight = 0;
  994.         } else {
  995.             x = menuPtr->borderWidth;
  996.             for (j = lastRowBreak; j < i; j++) {
  997.             menuPtr->entries[j]->y = y + currentRowHeight
  998.                     - menuPtr->entries[j]->height;
  999.             menuPtr->entries[j]->x = x;
  1000.             x += menuPtr->entries[j]->width;
  1001.             }
  1002.             lastRowBreak = i;
  1003.             y += currentRowHeight;
  1004.             currentRowHeight = itemHeight;
  1005.         }
  1006.         if (x > maxWidth) {
  1007.             maxWidth = x;
  1008.         }
  1009.         x = menuPtr->borderWidth;
  1010.         } else {
  1011.         x += mePtr->width;
  1012.         if (itemHeight > currentRowHeight) {
  1013.             currentRowHeight = itemHeight;
  1014.         }
  1015.         } 
  1016.     }
  1017.  
  1018.     lastEntry = menuPtr->numEntries - 1;
  1019.     if (helpMenuIndex == lastEntry) {
  1020.         lastEntry--;
  1021.     }
  1022.     if ((lastEntry >= 0) && (x + menuPtr->entries[lastEntry]->width
  1023.         + menuPtr->borderWidth > maxWidth)) {
  1024.         maxWidth = x + menuPtr->entries[lastEntry]->width
  1025.             + menuPtr->borderWidth;
  1026.     }
  1027.     x = menuPtr->borderWidth;
  1028.     for (j = lastRowBreak; j < menuPtr->numEntries; j++) {
  1029.         if (j == helpMenuIndex) {
  1030.         continue;
  1031.         }
  1032.         menuPtr->entries[j]->y = y + currentRowHeight
  1033.             - menuPtr->entries[j]->height;
  1034.         menuPtr->entries[j]->x = x;
  1035.         x += menuPtr->entries[j]->width;
  1036.     }
  1037.     
  1038.  
  1039.     if (helpMenuIndex != -1) {
  1040.         mePtr = menuPtr->entries[helpMenuIndex];
  1041.         if (x + mePtr->width + menuPtr->borderWidth > maxWindowWidth) {
  1042.         y += currentRowHeight;
  1043.         currentRowHeight = mePtr->height;
  1044.         x = menuPtr->borderWidth;
  1045.         } else if (mePtr->height > currentRowHeight) {
  1046.         currentRowHeight = mePtr->height;
  1047.         }
  1048.         mePtr->x = maxWindowWidth - menuPtr->borderWidth - mePtr->width;
  1049.         mePtr->y = y + currentRowHeight - mePtr->height;
  1050.     }
  1051.     height = y + currentRowHeight + menuPtr->borderWidth;
  1052.     }
  1053.     width = Tk_Width(menuPtr->tkwin);    
  1054.  
  1055.     /*
  1056.      * The X server doesn't like zero dimensions, so round up to at least
  1057.      * 1 (a zero-sized menu should never really occur, anyway).
  1058.      */
  1059.  
  1060.     if (width <= 0) {
  1061.     width = 1;
  1062.     }
  1063.     if (height <= 0) {
  1064.     height = 1;
  1065.     }
  1066.     menuPtr->totalWidth = maxWidth;
  1067.     menuPtr->totalHeight = height;
  1068. }
  1069.  
  1070. /*
  1071.  *----------------------------------------------------------------------
  1072.  *
  1073.  * DrawTearoffEntry --
  1074.  *
  1075.  *    This procedure draws the background part of a menu.
  1076.  *
  1077.  * Results:
  1078.  *    None.
  1079.  *
  1080.  * Side effects:
  1081.  *    Commands are output to X to display the menu in its
  1082.  *    current mode.
  1083.  *
  1084.  *----------------------------------------------------------------------
  1085.  */
  1086.  
  1087. static void
  1088. DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  1089.     TkMenu *menuPtr;            /* The menu we are drawing */
  1090.     TkMenuEntry *mePtr;            /* The entry we are drawing */
  1091.     Drawable d;                /* The drawable we are drawing into */
  1092.     GC gc;                /* The gc we are drawing with */
  1093.     Tk_Font tkfont;            /* The font we are drawing with */
  1094.     CONST Tk_FontMetrics *fmPtr;    /* The metrics we are drawing with */
  1095.     int x;
  1096.     int y;
  1097.     int width;
  1098.     int height;
  1099. {
  1100.     XPoint points[2];
  1101.     int margin, segmentWidth, maxX;
  1102.  
  1103.     if (menuPtr->menuType != MASTER_MENU) {
  1104.     return;
  1105.     }
  1106.     
  1107.     margin = (fmPtr->ascent + fmPtr->descent)/2;
  1108.     points[0].x = x;
  1109.     points[0].y = y + height/2;
  1110.     points[1].y = points[0].y;
  1111.     segmentWidth = 6;
  1112.     maxX  = width - 1;
  1113.  
  1114.     while (points[0].x < maxX) {
  1115.     points[1].x = points[0].x + segmentWidth;
  1116.     if (points[1].x > maxX) {
  1117.         points[1].x = maxX;
  1118.     }
  1119.     Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1,
  1120.         TK_RELIEF_RAISED);
  1121.     points[0].x += 2*segmentWidth;
  1122.     }
  1123. }
  1124.  
  1125. /*
  1126.  *--------------------------------------------------------------
  1127.  *
  1128.  * TkpInitializeMenuBindings --
  1129.  *
  1130.  *    For every interp, initializes the bindings for Windows
  1131.  *    menus. Does nothing on Mac or XWindows.
  1132.  *
  1133.  * Results:
  1134.  *    None.
  1135.  *
  1136.  * Side effects:
  1137.  *    C-level bindings are setup for the interp which will
  1138.  *    handle Alt-key sequences for menus without beeping
  1139.  *    or interfering with user-defined Alt-key bindings.
  1140.  *
  1141.  *--------------------------------------------------------------
  1142.  */
  1143.  
  1144. void
  1145. TkpInitializeMenuBindings(interp, bindingTable)
  1146.     Tcl_Interp *interp;            /* The interpreter to set. */
  1147.     Tk_BindingTable bindingTable;   /* The table to add to. */
  1148. {
  1149.     /*
  1150.      * Nothing to do.
  1151.      */
  1152. }
  1153.  
  1154. /*
  1155.  *----------------------------------------------------------------------
  1156.  *
  1157.  * SetHelpMenu --
  1158.  *
  1159.  *    Given a menu, check to see whether or not it is a help menu
  1160.  *    cascade in a menubar. If it is, the entry that points to
  1161.  *    this menu will be marked.
  1162.  *
  1163.  * RESULTS:
  1164.  *    None.
  1165.  *
  1166.  * Side effects:
  1167.  *    Will set the ENTRY_HELP_MENU flag appropriately.
  1168.  *
  1169.  *----------------------------------------------------------------------
  1170.  */
  1171.  
  1172. static void
  1173. SetHelpMenu(menuPtr)
  1174.      TkMenu *menuPtr;        /* The menu we are checking */
  1175. {
  1176.     TkMenuEntry *cascadeEntryPtr;
  1177.  
  1178.     for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
  1179.         cascadeEntryPtr != NULL;
  1180.         cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
  1181.     if ((cascadeEntryPtr->menuPtr->menuType == MENUBAR)
  1182.         && (cascadeEntryPtr->menuPtr->masterMenuPtr->tkwin != NULL)
  1183.         && (menuPtr->masterMenuPtr->tkwin != NULL)) {
  1184.         TkMenu *masterMenuPtr = cascadeEntryPtr->menuPtr->masterMenuPtr;
  1185.         char *helpMenuName = ckalloc(strlen(Tk_PathName(
  1186.             masterMenuPtr->tkwin)) + strlen(".help") + 1);
  1187.  
  1188.         strcpy(helpMenuName, Tk_PathName(masterMenuPtr->tkwin));
  1189.         strcat(helpMenuName, ".help");
  1190.         if (strcmp(helpMenuName,
  1191.             Tk_PathName(menuPtr->masterMenuPtr->tkwin)) == 0) {
  1192.         cascadeEntryPtr->entryFlags |= ENTRY_HELP_MENU;
  1193.         } else {
  1194.         cascadeEntryPtr->entryFlags &= ~ENTRY_HELP_MENU;
  1195.         }
  1196.         ckfree(helpMenuName);
  1197.     }
  1198.     }
  1199. }
  1200.  
  1201. /*
  1202.  *----------------------------------------------------------------------
  1203.  *
  1204.  * TkpDrawMenuEntry --
  1205.  *
  1206.  *    Draws the given menu entry at the given coordinates with the
  1207.  *    given attributes.
  1208.  *
  1209.  * Results:
  1210.  *    None.
  1211.  *
  1212.  * Side effects:
  1213.  *    X Server commands are executed to display the menu entry.
  1214.  *
  1215.  *----------------------------------------------------------------------
  1216.  */
  1217.  
  1218. void
  1219. TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, 
  1220.     strictMotif, drawArrow)
  1221.     TkMenuEntry *mePtr;            /* The entry to draw */
  1222.     Drawable d;                /* What to draw into */
  1223.     Tk_Font tkfont;            /* Precalculated font for menu */
  1224.     CONST Tk_FontMetrics *menuMetricsPtr;
  1225.                     /* Precalculated metrics for menu */
  1226.     int x;                /* X-coordinate of topleft of entry */
  1227.     int y;                /* Y-coordinate of topleft of entry */
  1228.     int width;                /* Width of the entry rectangle */
  1229.     int height;                /* Height of the current rectangle */
  1230.     int strictMotif;            /* Boolean flag */
  1231.     int drawArrow;            /* Whether or not to draw the cascade
  1232.                      * arrow for cascade items. Only applies
  1233.                      * to Windows. */
  1234. {
  1235.     GC gc, indicatorGC;
  1236.     TkMenu *menuPtr = mePtr->menuPtr;
  1237.     Tk_3DBorder bgBorder, activeBorder;
  1238.     CONST Tk_FontMetrics *fmPtr;
  1239.     Tk_FontMetrics entryMetrics;
  1240.     int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
  1241.     int adjustedY = y + padY;
  1242.     int adjustedHeight = height - 2 * padY;
  1243.  
  1244.     /*
  1245.      * Choose the gc for drawing the foreground part of the entry.
  1246.      */
  1247.  
  1248.     if ((mePtr->state == tkActiveUid)
  1249.         && !strictMotif) {
  1250.     gc = mePtr->activeGC;
  1251.     if (gc == NULL) {
  1252.         gc = menuPtr->activeGC;
  1253.     }
  1254.     } else {
  1255.         TkMenuEntry *cascadeEntryPtr;
  1256.         int parentDisabled = 0;
  1257.         
  1258.         for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
  1259.             cascadeEntryPtr != NULL;
  1260.             cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
  1261.             if (strcmp(cascadeEntryPtr->name, 
  1262.                     Tk_PathName(menuPtr->tkwin)) == 0) {
  1263.                 if (cascadeEntryPtr->state == tkDisabledUid) {
  1264.                     parentDisabled = 1;
  1265.                 }
  1266.                 break;
  1267.             }
  1268.         }
  1269.  
  1270.     if (((parentDisabled || (mePtr->state == tkDisabledUid)))
  1271.         && (menuPtr->disabledFg != NULL)) {
  1272.         gc = mePtr->disabledGC;
  1273.         if (gc == NULL) {
  1274.         gc = menuPtr->disabledGC;
  1275.         }
  1276.     } else {
  1277.         gc = mePtr->textGC;
  1278.         if (gc == NULL) {
  1279.         gc = menuPtr->textGC;
  1280.         }
  1281.     }
  1282.     }
  1283.     indicatorGC = mePtr->indicatorGC;
  1284.     if (indicatorGC == NULL) {
  1285.     indicatorGC = menuPtr->indicatorGC;
  1286.     }
  1287.         
  1288.     bgBorder = mePtr->border;
  1289.     if (bgBorder == NULL) {
  1290.     bgBorder = menuPtr->border;
  1291.     }
  1292.     if (strictMotif) {
  1293.     activeBorder = bgBorder;
  1294.     } else {
  1295.     activeBorder = mePtr->activeBorder;
  1296.     if (activeBorder == NULL) {
  1297.         activeBorder = menuPtr->activeBorder;
  1298.     }
  1299.     }
  1300.  
  1301.     if (mePtr->tkfont == NULL) {
  1302.     fmPtr = menuMetricsPtr;
  1303.     } else {
  1304.     tkfont = mePtr->tkfont;
  1305.     Tk_GetFontMetrics(tkfont, &entryMetrics);
  1306.     fmPtr = &entryMetrics;
  1307.     }
  1308.  
  1309.     /*
  1310.      * Need to draw the entire background, including padding. On Unix,
  1311.      * for menubars, we have to draw the rest of the entry taking
  1312.      * into account the padding.
  1313.      */
  1314.     
  1315.     DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, 
  1316.         bgBorder, x, y, width, height);
  1317.     
  1318.     if (mePtr->type == SEPARATOR_ENTRY) {
  1319.     DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, 
  1320.         fmPtr, x, adjustedY, width, adjustedHeight);
  1321.     } else if (mePtr->type == TEAROFF_ENTRY) {
  1322.     DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  1323.         width, adjustedHeight);
  1324.     } else {
  1325.     DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  1326.         width, adjustedHeight);
  1327.     DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
  1328.         activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
  1329.     if (!mePtr->hideMargin) {
  1330.         DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
  1331.             fmPtr, x, adjustedY, width, adjustedHeight);
  1332.     }
  1333.     }
  1334. }
  1335.  
  1336. /*
  1337.  *----------------------------------------------------------------------
  1338.  *
  1339.  * GetMenuLabelGeometry --
  1340.  *
  1341.  *    Figures out the size of the label portion of a menu item.
  1342.  *
  1343.  * Results:
  1344.  *    widthPtr and heightPtr are filled in with the correct geometry
  1345.  *    information.
  1346.  *
  1347.  * Side effects:
  1348.  *    None.
  1349.  *
  1350.  *----------------------------------------------------------------------
  1351.  */
  1352.  
  1353. static void
  1354. GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  1355.     TkMenuEntry *mePtr;            /* The entry we are computing */
  1356.     Tk_Font tkfont;            /* The precalculated font */
  1357.     CONST Tk_FontMetrics *fmPtr;    /* The precalculated metrics */
  1358.     int *widthPtr;            /* The resulting width of the label
  1359.                      * portion */
  1360.     int *heightPtr;            /* The resulting height of the label
  1361.                      * portion */
  1362. {
  1363.     TkMenu *menuPtr = mePtr->menuPtr;
  1364.  
  1365.     if (mePtr->image != NULL) {
  1366.         Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
  1367.     } else if (mePtr->bitmap != (Pixmap) NULL) {
  1368.         Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr);
  1369.     } else {
  1370.         *heightPtr = fmPtr->linespace;
  1371.         
  1372.         if (mePtr->label != NULL) {
  1373.             *widthPtr = Tk_TextWidth(tkfont, mePtr->label, mePtr->labelLength);
  1374.         } else {
  1375.             *widthPtr = 0;
  1376.         }
  1377.     }
  1378.     *heightPtr += 1;
  1379. }
  1380.  
  1381. /*
  1382.  *--------------------------------------------------------------
  1383.  *
  1384.  * TkpComputeStandardMenuGeometry --
  1385.  *
  1386.  *    This procedure is invoked to recompute the size and
  1387.  *    layout of a menu that is not a menubar clone.
  1388.  *
  1389.  * Results:
  1390.  *    None.
  1391.  *
  1392.  * Side effects:
  1393.  *    Fields of menu entries are changed to reflect their
  1394.  *    current positions, and the size of the menu window
  1395.  *    itself may be changed.
  1396.  *
  1397.  *--------------------------------------------------------------
  1398.  */
  1399.  
  1400. void
  1401. TkpComputeStandardMenuGeometry(
  1402.     menuPtr)        /* Structure describing menu. */
  1403.     TkMenu *menuPtr;
  1404. {
  1405.     Tk_Font tkfont;
  1406.     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
  1407.     int x, y, height, width, indicatorSpace, labelWidth, accelWidth;
  1408.     int windowWidth, windowHeight, accelSpace;
  1409.     int i, j, lastColumnBreak = 0;
  1410.     TkMenuEntry *mePtr;
  1411.     
  1412.     if (menuPtr->tkwin == NULL) {
  1413.     return;
  1414.     }
  1415.  
  1416.     x = y = menuPtr->borderWidth;
  1417.     indicatorSpace = labelWidth = accelWidth = 0;
  1418.     windowHeight = windowWidth = 0;
  1419.  
  1420.     /*
  1421.      * On the Mac especially, getting font metrics can be quite slow,
  1422.      * so we want to do it intelligently. We are going to precalculate
  1423.      * them and pass them down to all of the measuring and drawing
  1424.      * routines. We will measure the font metrics of the menu once.
  1425.      * If an entry does not have its own font set, then we give
  1426.      * the geometry/drawing routines the menu's font and metrics.
  1427.      * If an entry has its own font, we will measure that font and
  1428.      * give all of the geometry/drawing the entry's font and metrics.
  1429.      */
  1430.  
  1431.     Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics);
  1432.     accelSpace = Tk_TextWidth(menuPtr->tkfont, "M", 1);
  1433.  
  1434.     for (i = 0; i < menuPtr->numEntries; i++) {
  1435.     mePtr = menuPtr->entries[i];
  1436.         tkfont = mePtr->tkfont;
  1437.         if (tkfont == NULL) {
  1438.             tkfont = menuPtr->tkfont;
  1439.             fmPtr = &menuMetrics;
  1440.         } else {
  1441.             Tk_GetFontMetrics(tkfont, &entryMetrics);
  1442.             fmPtr = &entryMetrics;
  1443.         }
  1444.         
  1445.     if ((i > 0) && mePtr->columnBreak) {
  1446.         if (accelWidth != 0) {
  1447.         labelWidth += accelSpace;
  1448.         }
  1449.         for (j = lastColumnBreak; j < i; j++) {
  1450.         menuPtr->entries[j]->indicatorSpace = indicatorSpace;
  1451.         menuPtr->entries[j]->labelWidth = labelWidth;
  1452.         menuPtr->entries[j]->width = indicatorSpace + labelWidth
  1453.             + accelWidth + 2 * menuPtr->activeBorderWidth;
  1454.         menuPtr->entries[j]->x = x;
  1455.         menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN;
  1456.         }
  1457.         x += indicatorSpace + labelWidth + accelWidth
  1458.             + 2 * menuPtr->activeBorderWidth;
  1459.         windowWidth = x;
  1460.         indicatorSpace = labelWidth = accelWidth = 0;
  1461.         lastColumnBreak = i;
  1462.         y = menuPtr->borderWidth;
  1463.     }
  1464.  
  1465.     if (mePtr->type == SEPARATOR_ENTRY) {
  1466.         GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont,
  1467.                 fmPtr, &width, &height);
  1468.         mePtr->height = height;
  1469.     } else if (mePtr->type == TEAROFF_ENTRY) {
  1470.         GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, 
  1471.                 fmPtr, &width, &height);
  1472.         mePtr->height = height;
  1473.         labelWidth = width;
  1474.     } else {
  1475.         
  1476.         /*
  1477.          * For each entry, compute the height required by that
  1478.          * particular entry, plus three widths:  the width of the
  1479.          * label, the width to allow for an indicator to be displayed
  1480.          * to the left of the label (if any), and the width of the
  1481.          * accelerator to be displayed to the right of the label
  1482.          * (if any).  These sizes depend, of course, on the type
  1483.          * of the entry.
  1484.          */
  1485.         
  1486.         GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width,
  1487.                 &height);
  1488.         mePtr->height = height;
  1489.         if (!mePtr->hideMargin) {
  1490.         width += MENU_MARGIN_WIDTH;
  1491.         }
  1492.         if (width > labelWidth) {
  1493.             labelWidth = width;
  1494.         }
  1495.     
  1496.         GetMenuAccelGeometry(menuPtr, mePtr, tkfont,
  1497.             fmPtr, &width, &height);
  1498.         if (height > mePtr->height) {
  1499.             mePtr->height = height;
  1500.         }
  1501.         if (!mePtr->hideMargin) {
  1502.         width += MENU_MARGIN_WIDTH;
  1503.         }
  1504.         if (width > accelWidth) {
  1505.             accelWidth = width;
  1506.         }
  1507.  
  1508.         GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, 
  1509.                 fmPtr, &width, &height);
  1510.         if (height > mePtr->height) {
  1511.             mePtr->height = height;
  1512.         }
  1513.         if (!mePtr->hideMargin) {
  1514.         width += MENU_MARGIN_WIDTH;
  1515.         }
  1516.         if (width > indicatorSpace) {
  1517.             indicatorSpace = width;
  1518.         }
  1519.  
  1520.         mePtr->height += 2 * menuPtr->activeBorderWidth + 
  1521.                 MENU_DIVIDER_HEIGHT;
  1522.         }
  1523.         mePtr->y = y;
  1524.     y += mePtr->height;
  1525.     if (y > windowHeight) {
  1526.         windowHeight = y;
  1527.     }
  1528.     }
  1529.  
  1530.     if (accelWidth != 0) {
  1531.     labelWidth += accelSpace;
  1532.     }
  1533.     for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
  1534.     menuPtr->entries[j]->indicatorSpace = indicatorSpace;
  1535.     menuPtr->entries[j]->labelWidth = labelWidth;
  1536.     menuPtr->entries[j]->width = indicatorSpace + labelWidth
  1537.         + accelWidth + 2 * menuPtr->activeBorderWidth;
  1538.     menuPtr->entries[j]->x = x;
  1539.     menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN;
  1540.     }
  1541.     windowWidth = x + indicatorSpace + labelWidth + accelWidth
  1542.         + 2 * menuPtr->activeBorderWidth + 2 * menuPtr->borderWidth;
  1543.  
  1544.  
  1545.     windowHeight += menuPtr->borderWidth;
  1546.     
  1547.     /*
  1548.      * The X server doesn't like zero dimensions, so round up to at least
  1549.      * 1 (a zero-sized menu should never really occur, anyway).
  1550.      */
  1551.  
  1552.     if (windowWidth <= 0) {
  1553.     windowWidth = 1;
  1554.     }
  1555.     if (windowHeight <= 0) {
  1556.     windowHeight = 1;
  1557.     }
  1558.     menuPtr->totalWidth = windowWidth;
  1559.     menuPtr->totalHeight = windowHeight;
  1560. }
  1561.  
  1562. /*
  1563.  *----------------------------------------------------------------------
  1564.  *
  1565.  * TkpMenuNotifyToplevelCreate --
  1566.  *
  1567.  *    This routine reconfigures the menu and the clones indicated by
  1568.  *    menuName becuase a toplevel has been created and any system
  1569.  *    menus need to be created. Not applicable to UNIX.
  1570.  *
  1571.  * Results:
  1572.  *    None.
  1573.  *
  1574.  * Side effects:
  1575.  *    An idle handler is set up to do the reconfiguration.
  1576.  *
  1577.  *----------------------------------------------------------------------
  1578.  */
  1579.  
  1580. void
  1581. TkpMenuNotifyToplevelCreate(interp, menuName)
  1582.     Tcl_Interp *interp;            /* The interp the menu lives in. */
  1583.     char *menuName;            /* The name of the menu to 
  1584.                      * reconfigure. */
  1585. {
  1586.     /*
  1587.      * Nothing to do.
  1588.      */
  1589. }
  1590.  
  1591. /*
  1592.  *----------------------------------------------------------------------
  1593.  *
  1594.  * TkpMenuInit --
  1595.  *
  1596.  *    Does platform-specific initialization of menus.
  1597.  *
  1598.  * Results:
  1599.  *    None.
  1600.  *
  1601.  * Side effects:
  1602.  *    None.
  1603.  *
  1604.  *----------------------------------------------------------------------
  1605.  */
  1606.  
  1607. void
  1608. TkpMenuInit()
  1609. {
  1610.     /*
  1611.      * Nothing to do.
  1612.      */
  1613. }
  1614.